# Check requisite packages are installed.
packages <- c(
  "plotly", 
  "dplyr"
)
for (pkg in packages) {
  library(pkg, character.only = TRUE)
}

What do the results look like?

dirViking <- file.path(
  getwd(), "LCAB_LawMorton1996-NumericalPoolCommunityScaling"
)
dirVikingResults <- file.path(
  dirViking, "results-2021-04"
)
resultFormat <- paste0(
  "run-", 
  "%d", # Combination Number, or CombnNum.
  "-", 
  "%s", # Run Seed.
  ".RDS"
)
# Copied from LawMorton1996-NumericalPoolCommunityScaling-Calculation.R
# TODO: In the future, make this a separate file that everyone can call...
set.seed(38427042)

basal <- c(3, 10, 30, 100, 300, 1000)
consumer <- c(3, 10, 30, 100, 300, 1000) * 2
events <- (max(basal) + max(consumer)) * 2
runs <- 100

logBodySize <- c(-2, -1, -1, 1) # Morton and Law 1997 version.
parameters <- c(0.01, 10, 0.5, 0.2, 100, 0.1)

# Need to rerun seedsPrep to get the random number generation right for seedsRun
seedsPrep <- runif(2 * length(basal) * length(consumer)) * 1E8
seedsRun <- runif(runs * length(basal) * length(consumer)) * 1E8
paramFrame <- with(list(
  b = rep(basal, times = length(consumer)),
  c = rep(consumer, each = length(basal)),
  s1 = seedsPrep[1:(length(basal) * length(consumer))],
  s2 = seedsPrep[
    (length(basal) * length(consumer) + 1):(
      2 * length(basal) * length(consumer))
  ],
  sR = seedsRun
), {
  temp <- data.frame(
    CombnNum = 0,
    Basals = b,
    Consumers = c,
    SeedPool = s1,
    SeedMat = s2,
    SeedRuns = "",
    SeedRunsNum = 0,
    EndStates = I(rep(list(""), length(b))),
    EndStatesNum = 0,
    EndStateSizes = I(rep(list(""), length(b)))
  )
  for (i in 1:nrow(temp)) {
    seeds <- sR[((i - 1) * runs + 1) : (i * runs)]
    temp$SeedRuns[i] <- toString(seeds) # CSV
    temp$SeedRunsNum[i] <- length(seeds)
  }
  temp$CombnNum <- 1:nrow(temp)
  temp
})
# Note: n + 2 end states. Failure to finish, failure to obtain state, and state.
for (i in 1:nrow(paramFrame)) {
  resultsList <- list(
    "No Run" = 0,
    "No State" = 0
  )
  resultsSize <- list(
    "0" = 0
  )
  seeds <- unlist(strsplit(paramFrame$SeedRuns[i], ', '))
  for (seed in seeds) {
    fileName <- file.path(
      dirVikingResults,
      sprintf(resultFormat, paramFrame$CombnNum[i], seed)
    )
    
    if (file.exists(fileName)) {
      temp <- load(fileName)
      temp <- eval(parse(text = temp)) # Get objects.
      
      if (is.data.frame(temp)) {
        community <- toString(
          temp[[ncol(temp)]][[nrow(temp)]]
        )
        size <- toString(length(temp[[ncol(temp)]][[nrow(temp)]]))
        
        if (community == "") {
          resultsList$`No State` <- resultsList$`No State` + 1
          resultsSize$`0` <- resultsSize$`0` + 1
          
        } else if (community %in% names(resultsList)) {
          resultsList[[community]] <- resultsList[[community]] + 1
          resultsSize[[size]] <- resultsSize[[size]] + 1
          
        } else {
          resultsList[[community]] <- 1
          
          if (size %in% resultsSize) {
            resultsSize[[size]] <- resultsSize[[size]] + 1
          } else {
            resultsSize[[size]] <- 1
          }
        }
      } else {
        resultsList$`No State` <- resultsList$`No State` + 1
        resultsSize$`0` <- resultsSize$`0` + 1
      }
    } else {
      resultsList$`No Run` <- resultsList$`No Run` + 1
      resultsSize$`0` <- resultsSize$`0` + 1
    }
  }
  
  paramFrame$EndStates[[i]] <- resultsList
  paramFrame$EndStatesNum[i] <- length(resultsList) - 2 # ! No State, No Run
  paramFrame$EndStateSizes[[i]] <- resultsSize
  paramFrame$EndStateSizesNum[i] <- length(resultsSize) - 1 # ! 0
}
# X, Y, Basal and Consumer.
# Z = Sizes of the Endstates.

plotScalingData <- data.frame(
  CombnNum = rep(paramFrame$CombnNum, paramFrame$EndStatesNum),
  Basals = rep(paramFrame$Basals, paramFrame$EndStatesNum),
  Consumers = rep(paramFrame$Consumers, paramFrame$EndStatesNum)
)

# Communities
comms <- unlist(lapply(paramFrame$EndStates, names))
freqs <- unlist(paramFrame$EndStates)
freqs <- freqs[comms != "No Run" & comms != "No State"]
comms <- comms[comms != "No Run" & comms != "No State"]

plotScalingData$Communities <- comms
plotScalingData$CommunityFreq <- freqs

# Community Size
temp <- unlist(lapply(strsplit(plotScalingData$Communities, ','), length))
plotScalingData$CommunitySize <- temp

# For usage by the reader.

plotScaling <- plotly::plot_ly(
  plotScalingData,
  x = ~Basals,
  y = ~Consumers,
  z = ~CommunitySize
)

plotScaling <- plotly::add_markers(plotScaling)

plotScaling <- plotly::layout(
  plotScaling,
  scene = list(
    xaxis = list(type = "log"),
    yaxis = list(type = "log")
  )
)

plotScaling
plotScalingData

How do they compare to each other?

# > runif(1) * 1E8
# [1] 82598679
set.seed(82598679)

temp <- load(file.path(
  dirViking, 
  "LawMorton1996-NumericalPoolCommunityScaling-PoolMats.RDS"
))
mats  <- eval(parse(text = temp[1]))
pools <- eval(parse(text = temp[2]))
plotScalingData$CommunityAbund <- ""
for (r in 1:nrow(plotScalingData)) {
  plotScalingData$CommunityAbund[r] <- with(plotScalingData[r, ], toString(
    RMTRCode2::FindSteadyStateFromEstimate(
      Pool = pools[[CombnNum]], 
      InteractionMatrix = mats[[CombnNum]], 
      Community = Communities, 
      Populations = rep(100, CommunitySize), # No good guesses here
      maxRandVal = 2E4, # 2 * round of the largest value we have seen so far.
      MaxAttempts = 1E4,
      Verbose = FALSE
    )
  ))
}
Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.Failed to converge after 10000 attempts.
plotScalingData$CommunityProd <- NA
for (r in 1:nrow(plotScalingData)) {
  plotScalingData$CommunityProd[r] <- with(plotScalingData[r, ], 
    RMTRCode2::Productivity(
      Pool = pools[[CombnNum]], 
      InteractionMatrix = mats[[CombnNum]], 
      Community = Communities, 
      Populations = CommunityAbund
    )
  )
}
candidateData <- plotScalingData %>% dplyr::group_by(
  CombnNum
) %>% dplyr::mutate(
  OtherSteadyStates = dplyr::n() - 1
) %>% dplyr::filter(
  OtherSteadyStates > 0
)
candidateData %>% dplyr::select(-CommunityAbund)
islandFUN <- function(i, dat, pool, mat, dmat) {
      temp <- dat[i, ]
      RMTRCode2::IslandDynamics(
        Pool = pool,
        InteractionMatrix = mat,
        Communities = c(
          list(temp$Communities[1]),
          rep("", nrow(dmat) - 2),
          temp$Communities[2]
        ),
        Populations = c(
          list(temp$CommunityAbund[1]),
          rep("", nrow(dmat) - 2),
          list(temp$CommunityAbund[2])
        ),
        DispersalPool = 0.0001,
        DispersalIsland = dmat,
      )
    }
# For each group,
# For each pair,
# Run Island Dynamics,
# Save the result with its pairing

for (grp in unique(candidateData$CombnNum)) {
  candidateDataSubset <- candidateData %>% dplyr::filter(CombnNum == grp)
  pairingResults<- combn(
    nrow(candidateDataSubset), 2, 
    islandFUN,
    dat = candidateDataSubset, 
    pool = pools[[grp]],
    mat = mats[[grp]],
    dmat = matrix(c(0, 1, 1, 0), nrow = 2, ncol = 2),
    simplify = FALSE
  )
}
for (grp in unique(candidateData$CombnNum)) {
  candidateDataSubset <- candidateData %>% dplyr::filter(CombnNum == grp)
  pairingResults<- combn(
    nrow(candidateDataSubset), 2, 
    islandFUN,
    dat = candidateDataSubset, 
    pool = pools[[grp]],
    mat = mats[[grp]],
    dmat = matrix(c(
      0, 1, 0, # Island 2 -> 1
      1, 0, 1, # Island 1 -> 2, Island 3 -> 2
      0, 1, 0  # Island 2 -> 3
    ), nrow = 3, ncol = 3, byrow = TRUE),
    simplify = FALSE
  )
}
LS0tDQp0aXRsZTogIlZpa2luZyBSZXN1bHRzLCAyMDIxLTA0Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KLS0tDQoNCmBgYHtyIGxpYnN9DQojIENoZWNrIHJlcXVpc2l0ZSBwYWNrYWdlcyBhcmUgaW5zdGFsbGVkLg0KcGFja2FnZXMgPC0gYygNCiAgInBsb3RseSIsIA0KICAiZHBseXIiDQopDQpmb3IgKHBrZyBpbiBwYWNrYWdlcykgew0KICBsaWJyYXJ5KHBrZywgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KfQ0KYGBgDQoNCiMgV2hhdCBkbyB0aGUgcmVzdWx0cyBsb29rIGxpa2U/DQpgYGB7ciBkaXJzfQ0KZGlyVmlraW5nIDwtIGZpbGUucGF0aCgNCiAgZ2V0d2QoKSwgIkxDQUJfTGF3TW9ydG9uMTk5Ni1OdW1lcmljYWxQb29sQ29tbXVuaXR5U2NhbGluZyINCikNCmRpclZpa2luZ1Jlc3VsdHMgPC0gZmlsZS5wYXRoKA0KICBkaXJWaWtpbmcsICJyZXN1bHRzLTIwMjEtMDQiDQopDQpyZXN1bHRGb3JtYXQgPC0gcGFzdGUwKA0KICAicnVuLSIsIA0KICAiJWQiLCAjIENvbWJpbmF0aW9uIE51bWJlciwgb3IgQ29tYm5OdW0uDQogICItIiwgDQogICIlcyIsICMgUnVuIFNlZWQuDQogICIuUkRTIg0KKQ0KYGBgDQoNCmBgYHtyIHBhcmFtc30NCiMgQ29waWVkIGZyb20gTGF3TW9ydG9uMTk5Ni1OdW1lcmljYWxQb29sQ29tbXVuaXR5U2NhbGluZy1DYWxjdWxhdGlvbi5SDQojIFRPRE86IEluIHRoZSBmdXR1cmUsIG1ha2UgdGhpcyBhIHNlcGFyYXRlIGZpbGUgdGhhdCBldmVyeW9uZSBjYW4gY2FsbC4uLg0Kc2V0LnNlZWQoMzg0MjcwNDIpDQoNCmJhc2FsIDwtIGMoMywgMTAsIDMwLCAxMDAsIDMwMCwgMTAwMCkNCmNvbnN1bWVyIDwtIGMoMywgMTAsIDMwLCAxMDAsIDMwMCwgMTAwMCkgKiAyDQpldmVudHMgPC0gKG1heChiYXNhbCkgKyBtYXgoY29uc3VtZXIpKSAqIDINCnJ1bnMgPC0gMTAwDQoNCmxvZ0JvZHlTaXplIDwtIGMoLTIsIC0xLCAtMSwgMSkgIyBNb3J0b24gYW5kIExhdyAxOTk3IHZlcnNpb24uDQpwYXJhbWV0ZXJzIDwtIGMoMC4wMSwgMTAsIDAuNSwgMC4yLCAxMDAsIDAuMSkNCg0KIyBOZWVkIHRvIHJlcnVuIHNlZWRzUHJlcCB0byBnZXQgdGhlIHJhbmRvbSBudW1iZXIgZ2VuZXJhdGlvbiByaWdodCBmb3Igc2VlZHNSdW4NCnNlZWRzUHJlcCA8LSBydW5pZigyICogbGVuZ3RoKGJhc2FsKSAqIGxlbmd0aChjb25zdW1lcikpICogMUU4DQpzZWVkc1J1biA8LSBydW5pZihydW5zICogbGVuZ3RoKGJhc2FsKSAqIGxlbmd0aChjb25zdW1lcikpICogMUU4DQpgYGANCg0KYGBge3Igb3JnYW5pc2VQYXJhbXN9DQpwYXJhbUZyYW1lIDwtIHdpdGgobGlzdCgNCiAgYiA9IHJlcChiYXNhbCwgdGltZXMgPSBsZW5ndGgoY29uc3VtZXIpKSwNCiAgYyA9IHJlcChjb25zdW1lciwgZWFjaCA9IGxlbmd0aChiYXNhbCkpLA0KICBzMSA9IHNlZWRzUHJlcFsxOihsZW5ndGgoYmFzYWwpICogbGVuZ3RoKGNvbnN1bWVyKSldLA0KICBzMiA9IHNlZWRzUHJlcFsNCiAgICAobGVuZ3RoKGJhc2FsKSAqIGxlbmd0aChjb25zdW1lcikgKyAxKTooDQogICAgICAyICogbGVuZ3RoKGJhc2FsKSAqIGxlbmd0aChjb25zdW1lcikpDQogIF0sDQogIHNSID0gc2VlZHNSdW4NCiksIHsNCiAgdGVtcCA8LSBkYXRhLmZyYW1lKA0KICAgIENvbWJuTnVtID0gMCwNCiAgICBCYXNhbHMgPSBiLA0KICAgIENvbnN1bWVycyA9IGMsDQogICAgU2VlZFBvb2wgPSBzMSwNCiAgICBTZWVkTWF0ID0gczIsDQogICAgU2VlZFJ1bnMgPSAiIiwNCiAgICBTZWVkUnVuc051bSA9IDAsDQogICAgRW5kU3RhdGVzID0gSShyZXAobGlzdCgiIiksIGxlbmd0aChiKSkpLA0KICAgIEVuZFN0YXRlc051bSA9IDAsDQogICAgRW5kU3RhdGVTaXplcyA9IEkocmVwKGxpc3QoIiIpLCBsZW5ndGgoYikpKQ0KICApDQogIGZvciAoaSBpbiAxOm5yb3codGVtcCkpIHsNCiAgICBzZWVkcyA8LSBzUlsoKGkgLSAxKSAqIHJ1bnMgKyAxKSA6IChpICogcnVucyldDQogICAgdGVtcCRTZWVkUnVuc1tpXSA8LSB0b1N0cmluZyhzZWVkcykgIyBDU1YNCiAgICB0ZW1wJFNlZWRSdW5zTnVtW2ldIDwtIGxlbmd0aChzZWVkcykNCiAgfQ0KICB0ZW1wJENvbWJuTnVtIDwtIDE6bnJvdyh0ZW1wKQ0KICB0ZW1wDQp9KQ0KYGBgDQoNCmBgYHtyIGxvYWRSZXN1bHRzfQ0KIyBOb3RlOiBuICsgMiBlbmQgc3RhdGVzLiBGYWlsdXJlIHRvIGZpbmlzaCwgZmFpbHVyZSB0byBvYnRhaW4gc3RhdGUsIGFuZCBzdGF0ZS4NCmZvciAoaSBpbiAxOm5yb3cocGFyYW1GcmFtZSkpIHsNCiAgcmVzdWx0c0xpc3QgPC0gbGlzdCgNCiAgICAiTm8gUnVuIiA9IDAsDQogICAgIk5vIFN0YXRlIiA9IDANCiAgKQ0KICByZXN1bHRzU2l6ZSA8LSBsaXN0KA0KICAgICIwIiA9IDANCiAgKQ0KICBzZWVkcyA8LSB1bmxpc3Qoc3Ryc3BsaXQocGFyYW1GcmFtZSRTZWVkUnVuc1tpXSwgJywgJykpDQogIGZvciAoc2VlZCBpbiBzZWVkcykgew0KICAgIGZpbGVOYW1lIDwtIGZpbGUucGF0aCgNCiAgICAgIGRpclZpa2luZ1Jlc3VsdHMsDQogICAgICBzcHJpbnRmKHJlc3VsdEZvcm1hdCwgcGFyYW1GcmFtZSRDb21ibk51bVtpXSwgc2VlZCkNCiAgICApDQogICAgDQogICAgaWYgKGZpbGUuZXhpc3RzKGZpbGVOYW1lKSkgew0KICAgICAgdGVtcCA8LSBsb2FkKGZpbGVOYW1lKQ0KICAgICAgdGVtcCA8LSBldmFsKHBhcnNlKHRleHQgPSB0ZW1wKSkgIyBHZXQgb2JqZWN0cy4NCiAgICAgIA0KICAgICAgaWYgKGlzLmRhdGEuZnJhbWUodGVtcCkpIHsNCiAgICAgICAgY29tbXVuaXR5IDwtIHRvU3RyaW5nKA0KICAgICAgICAgIHRlbXBbW25jb2wodGVtcCldXVtbbnJvdyh0ZW1wKV1dDQogICAgICAgICkNCiAgICAgICAgc2l6ZSA8LSB0b1N0cmluZyhsZW5ndGgodGVtcFtbbmNvbCh0ZW1wKV1dW1tucm93KHRlbXApXV0pKQ0KICAgICAgICANCiAgICAgICAgaWYgKGNvbW11bml0eSA9PSAiIikgew0KICAgICAgICAgIHJlc3VsdHNMaXN0JGBObyBTdGF0ZWAgPC0gcmVzdWx0c0xpc3QkYE5vIFN0YXRlYCArIDENCiAgICAgICAgICByZXN1bHRzU2l6ZSRgMGAgPC0gcmVzdWx0c1NpemUkYDBgICsgMQ0KICAgICAgICAgIA0KICAgICAgICB9IGVsc2UgaWYgKGNvbW11bml0eSAlaW4lIG5hbWVzKHJlc3VsdHNMaXN0KSkgew0KICAgICAgICAgIHJlc3VsdHNMaXN0W1tjb21tdW5pdHldXSA8LSByZXN1bHRzTGlzdFtbY29tbXVuaXR5XV0gKyAxDQogICAgICAgICAgcmVzdWx0c1NpemVbW3NpemVdXSA8LSByZXN1bHRzU2l6ZVtbc2l6ZV1dICsgMQ0KICAgICAgICAgIA0KICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgIHJlc3VsdHNMaXN0W1tjb21tdW5pdHldXSA8LSAxDQogICAgICAgICAgDQogICAgICAgICAgaWYgKHNpemUgJWluJSByZXN1bHRzU2l6ZSkgew0KICAgICAgICAgICAgcmVzdWx0c1NpemVbW3NpemVdXSA8LSByZXN1bHRzU2l6ZVtbc2l6ZV1dICsgMQ0KICAgICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgICByZXN1bHRzU2l6ZVtbc2l6ZV1dIDwtIDENCiAgICAgICAgICB9DQogICAgICAgIH0NCiAgICAgIH0gZWxzZSB7DQogICAgICAgIHJlc3VsdHNMaXN0JGBObyBTdGF0ZWAgPC0gcmVzdWx0c0xpc3QkYE5vIFN0YXRlYCArIDENCiAgICAgICAgcmVzdWx0c1NpemUkYDBgIDwtIHJlc3VsdHNTaXplJGAwYCArIDENCiAgICAgIH0NCiAgICB9IGVsc2Ugew0KICAgICAgcmVzdWx0c0xpc3QkYE5vIFJ1bmAgPC0gcmVzdWx0c0xpc3QkYE5vIFJ1bmAgKyAxDQogICAgICByZXN1bHRzU2l6ZSRgMGAgPC0gcmVzdWx0c1NpemUkYDBgICsgMQ0KICAgIH0NCiAgfQ0KICANCiAgcGFyYW1GcmFtZSRFbmRTdGF0ZXNbW2ldXSA8LSByZXN1bHRzTGlzdA0KICBwYXJhbUZyYW1lJEVuZFN0YXRlc051bVtpXSA8LSBsZW5ndGgocmVzdWx0c0xpc3QpIC0gMiAjICEgTm8gU3RhdGUsIE5vIFJ1bg0KICBwYXJhbUZyYW1lJEVuZFN0YXRlU2l6ZXNbW2ldXSA8LSByZXN1bHRzU2l6ZQ0KICBwYXJhbUZyYW1lJEVuZFN0YXRlU2l6ZXNOdW1baV0gPC0gbGVuZ3RoKHJlc3VsdHNTaXplKSAtIDEgIyAhIDANCn0NCmBgYA0KDQo8IS0tYGBge3Igc2hvd1Jlc3VsdHN9DQpwYXJhbUZyYW1lWywgYygxOjMsIDg6MTApXQ0KYGBgLS0+DQoNCmBgYHtyIHBsb3QzRH0NCiMgWCwgWSwgQmFzYWwgYW5kIENvbnN1bWVyLg0KIyBaID0gU2l6ZXMgb2YgdGhlIEVuZHN0YXRlcy4NCg0KcGxvdFNjYWxpbmdEYXRhIDwtIGRhdGEuZnJhbWUoDQogIENvbWJuTnVtID0gcmVwKHBhcmFtRnJhbWUkQ29tYm5OdW0sIHBhcmFtRnJhbWUkRW5kU3RhdGVzTnVtKSwNCiAgQmFzYWxzID0gcmVwKHBhcmFtRnJhbWUkQmFzYWxzLCBwYXJhbUZyYW1lJEVuZFN0YXRlc051bSksDQogIENvbnN1bWVycyA9IHJlcChwYXJhbUZyYW1lJENvbnN1bWVycywgcGFyYW1GcmFtZSRFbmRTdGF0ZXNOdW0pDQopDQoNCiMgQ29tbXVuaXRpZXMNCmNvbW1zIDwtIHVubGlzdChsYXBwbHkocGFyYW1GcmFtZSRFbmRTdGF0ZXMsIG5hbWVzKSkNCmZyZXFzIDwtIHVubGlzdChwYXJhbUZyYW1lJEVuZFN0YXRlcykNCmZyZXFzIDwtIGZyZXFzW2NvbW1zICE9ICJObyBSdW4iICYgY29tbXMgIT0gIk5vIFN0YXRlIl0NCmNvbW1zIDwtIGNvbW1zW2NvbW1zICE9ICJObyBSdW4iICYgY29tbXMgIT0gIk5vIFN0YXRlIl0NCg0KcGxvdFNjYWxpbmdEYXRhJENvbW11bml0aWVzIDwtIGNvbW1zDQpwbG90U2NhbGluZ0RhdGEkQ29tbXVuaXR5RnJlcSA8LSBmcmVxcw0KDQojIENvbW11bml0eSBTaXplDQp0ZW1wIDwtIHVubGlzdChsYXBwbHkoc3Ryc3BsaXQocGxvdFNjYWxpbmdEYXRhJENvbW11bml0aWVzLCAnLCcpLCBsZW5ndGgpKQ0KcGxvdFNjYWxpbmdEYXRhJENvbW11bml0eVNpemUgPC0gdGVtcA0KDQojIEZvciB1c2FnZSBieSB0aGUgcmVhZGVyLg0KDQpwbG90U2NhbGluZyA8LSBwbG90bHk6OnBsb3RfbHkoDQogIHBsb3RTY2FsaW5nRGF0YSwNCiAgeCA9IH5CYXNhbHMsDQogIHkgPSB+Q29uc3VtZXJzLA0KICB6ID0gfkNvbW11bml0eVNpemUNCikNCg0KcGxvdFNjYWxpbmcgPC0gcGxvdGx5OjphZGRfbWFya2VycyhwbG90U2NhbGluZykNCg0KcGxvdFNjYWxpbmcgPC0gcGxvdGx5OjpsYXlvdXQoDQogIHBsb3RTY2FsaW5nLA0KICBzY2VuZSA9IGxpc3QoDQogICAgeGF4aXMgPSBsaXN0KHR5cGUgPSAibG9nIiksDQogICAgeWF4aXMgPSBsaXN0KHR5cGUgPSAibG9nIikNCiAgKQ0KKQ0KDQpwbG90U2NhbGluZw0KYGBgDQpgYGB7ciBwbG90M2REYXRhfQ0KcGxvdFNjYWxpbmdEYXRhDQpgYGANCiMgSG93IGRvIHRoZXkgY29tcGFyZSB0byBlYWNoIG90aGVyPw0KDQpgYGB7ciBsb2FkUG9vbHNNYXRzfQ0KIyA+IHJ1bmlmKDEpICogMUU4DQojIFsxXSA4MjU5ODY3OQ0Kc2V0LnNlZWQoODI1OTg2NzkpDQoNCnRlbXAgPC0gbG9hZChmaWxlLnBhdGgoDQogIGRpclZpa2luZywgDQogICJMYXdNb3J0b24xOTk2LU51bWVyaWNhbFBvb2xDb21tdW5pdHlTY2FsaW5nLVBvb2xNYXRzLlJEUyINCikpDQptYXRzICA8LSBldmFsKHBhcnNlKHRleHQgPSB0ZW1wWzFdKSkNCnBvb2xzIDwtIGV2YWwocGFyc2UodGV4dCA9IHRlbXBbMl0pKQ0KYGBgDQoNCmBgYHtyIGNvbXB1dGVQb3B1bGF0aW9uc30NCnBsb3RTY2FsaW5nRGF0YSRDb21tdW5pdHlBYnVuZCA8LSAiIg0KZm9yIChyIGluIDE6bnJvdyhwbG90U2NhbGluZ0RhdGEpKSB7DQogIHBsb3RTY2FsaW5nRGF0YSRDb21tdW5pdHlBYnVuZFtyXSA8LSB3aXRoKHBsb3RTY2FsaW5nRGF0YVtyLCBdLCB0b1N0cmluZygNCiAgICBSTVRSQ29kZTI6OkZpbmRTdGVhZHlTdGF0ZUZyb21Fc3RpbWF0ZSgNCiAgICAgIFBvb2wgPSBwb29sc1tbQ29tYm5OdW1dXSwgDQogICAgICBJbnRlcmFjdGlvbk1hdHJpeCA9IG1hdHNbW0NvbWJuTnVtXV0sIA0KICAgICAgQ29tbXVuaXR5ID0gQ29tbXVuaXRpZXMsIA0KICAgICAgUG9wdWxhdGlvbnMgPSByZXAoMTAwLCBDb21tdW5pdHlTaXplKSwgIyBObyBnb29kIGd1ZXNzZXMgaGVyZQ0KICAgICAgbWF4UmFuZFZhbCA9IDJFNCwgIyAyICogcm91bmQgb2YgdGhlIGxhcmdlc3QgdmFsdWUgd2UgaGF2ZSBzZWVuIHNvIGZhci4NCiAgICAgIE1heEF0dGVtcHRzID0gMUU0LA0KICAgICAgVmVyYm9zZSA9IEZBTFNFDQogICAgKQ0KICApKQ0KfQ0KYGBgDQoNCmBgYHtyIGNvbXB1dGVQcm9kdWN0aXZpdHl9DQpwbG90U2NhbGluZ0RhdGEkQ29tbXVuaXR5UHJvZCA8LSBOQQ0KZm9yIChyIGluIDE6bnJvdyhwbG90U2NhbGluZ0RhdGEpKSB7DQogIHBsb3RTY2FsaW5nRGF0YSRDb21tdW5pdHlQcm9kW3JdIDwtIHdpdGgocGxvdFNjYWxpbmdEYXRhW3IsIF0sIA0KICAgIFJNVFJDb2RlMjo6UHJvZHVjdGl2aXR5KA0KICAgICAgUG9vbCA9IHBvb2xzW1tDb21ibk51bV1dLCANCiAgICAgIEludGVyYWN0aW9uTWF0cml4ID0gbWF0c1tbQ29tYm5OdW1dXSwgDQogICAgICBDb21tdW5pdHkgPSBDb21tdW5pdGllcywgDQogICAgICBQb3B1bGF0aW9ucyA9IENvbW11bml0eUFidW5kDQogICAgKQ0KICApDQp9DQpgYGANCg0KYGBge3IgY29tcHV0ZUNhbmRpZGF0ZXN9DQpjYW5kaWRhdGVEYXRhIDwtIHBsb3RTY2FsaW5nRGF0YSAlPiUgZHBseXI6Omdyb3VwX2J5KA0KICBDb21ibk51bQ0KKSAlPiUgZHBseXI6Om11dGF0ZSgNCiAgT3RoZXJTdGVhZHlTdGF0ZXMgPSBkcGx5cjo6bigpIC0gMQ0KKSAlPiUgZHBseXI6OmZpbHRlcigNCiAgT3RoZXJTdGVhZHlTdGF0ZXMgPiAwDQopDQpjYW5kaWRhdGVEYXRhICU+JSBkcGx5cjo6c2VsZWN0KC1Db21tdW5pdHlBYnVuZCkNCmBgYA0KDQpgYGB7ciBpc2xhbmRGVU59DQppc2xhbmRGVU4gPC0gZnVuY3Rpb24oaSwgZGF0LCBwb29sLCBtYXQsIGRtYXQpIHsNCiAgICAgIHRlbXAgPC0gZGF0W2ksIF0NCiAgICAgIFJNVFJDb2RlMjo6SXNsYW5kRHluYW1pY3MoDQogICAgICAgIFBvb2wgPSBwb29sLA0KICAgICAgICBJbnRlcmFjdGlvbk1hdHJpeCA9IG1hdCwNCiAgICAgICAgQ29tbXVuaXRpZXMgPSBjKA0KICAgICAgICAgIGxpc3QodGVtcCRDb21tdW5pdGllc1sxXSksDQogICAgICAgICAgcmVwKCIiLCBucm93KGRtYXQpIC0gMiksDQogICAgICAgICAgdGVtcCRDb21tdW5pdGllc1syXQ0KICAgICAgICApLA0KICAgICAgICBQb3B1bGF0aW9ucyA9IGMoDQogICAgICAgICAgbGlzdCh0ZW1wJENvbW11bml0eUFidW5kWzFdKSwNCiAgICAgICAgICByZXAoIiIsIG5yb3coZG1hdCkgLSAyKSwNCiAgICAgICAgICBsaXN0KHRlbXAkQ29tbXVuaXR5QWJ1bmRbMl0pDQogICAgICAgICksDQogICAgICAgIERpc3BlcnNhbFBvb2wgPSAwLjAwMDEsDQogICAgICAgIERpc3BlcnNhbElzbGFuZCA9IGRtYXQsDQogICAgICApDQogICAgfQ0KYGBgDQoNCmBgYHtyIGlzbGFuZE9uZVR3b30NCiMgRm9yIGVhY2ggZ3JvdXAsDQojIEZvciBlYWNoIHBhaXIsDQojIFJ1biBJc2xhbmQgRHluYW1pY3MsDQojIFNhdmUgdGhlIHJlc3VsdCB3aXRoIGl0cyBwYWlyaW5nDQoNCmZvciAoZ3JwIGluIHVuaXF1ZShjYW5kaWRhdGVEYXRhJENvbWJuTnVtKSkgew0KICBjYW5kaWRhdGVEYXRhU3Vic2V0IDwtIGNhbmRpZGF0ZURhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQ29tYm5OdW0gPT0gZ3JwKQ0KICBwYWlyaW5nUmVzdWx0czwtIGNvbWJuKA0KICAgIG5yb3coY2FuZGlkYXRlRGF0YVN1YnNldCksIDIsIA0KICAgIGlzbGFuZEZVTiwNCiAgICBkYXQgPSBjYW5kaWRhdGVEYXRhU3Vic2V0LCANCiAgICBwb29sID0gcG9vbHNbW2dycF1dLA0KICAgIG1hdCA9IG1hdHNbW2dycF1dLA0KICAgIGRtYXQgPSBtYXRyaXgoYygwLCAxLCAxLCAwKSwgbnJvdyA9IDIsIG5jb2wgPSAyKSwNCiAgICBzaW1wbGlmeSA9IEZBTFNFDQogICkNCn0NCmBgYA0KDQpgYGB7ciBpc2xhbmRPbmVFbXB0eVR3b30NCmZvciAoZ3JwIGluIHVuaXF1ZShjYW5kaWRhdGVEYXRhJENvbWJuTnVtKSkgew0KICBjYW5kaWRhdGVEYXRhU3Vic2V0IDwtIGNhbmRpZGF0ZURhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoQ29tYm5OdW0gPT0gZ3JwKQ0KICBwYWlyaW5nUmVzdWx0czwtIGNvbWJuKA0KICAgIG5yb3coY2FuZGlkYXRlRGF0YVN1YnNldCksIDIsIA0KICAgIGlzbGFuZEZVTiwNCiAgICBkYXQgPSBjYW5kaWRhdGVEYXRhU3Vic2V0LCANCiAgICBwb29sID0gcG9vbHNbW2dycF1dLA0KICAgIG1hdCA9IG1hdHNbW2dycF1dLA0KICAgIGRtYXQgPSBtYXRyaXgoYygNCiAgICAgIDAsIDEsIDAsICMgSXNsYW5kIDIgLT4gMQ0KICAgICAgMSwgMCwgMSwgIyBJc2xhbmQgMSAtPiAyLCBJc2xhbmQgMyAtPiAyDQogICAgICAwLCAxLCAwICAjIElzbGFuZCAyIC0+IDMNCiAgICApLCBucm93ID0gMywgbmNvbCA9IDMsIGJ5cm93ID0gVFJVRSksDQogICAgc2ltcGxpZnkgPSBGQUxTRQ0KICApDQp9DQpgYGANCg==